﻿using System;
using System.Linq;
using System.Runtime.Serialization;
using BrainTechLLC.Communication;
using BrainTechLLC;
using System.Net;
using BrainTechLLC.ThreadSafeObjects;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Collections.Generic;
using System.Text;
using UserInterface;
using System.Collections.ObjectModel;
using System.IO;
using Mud.EmlenMudMain;

namespace BrainTechLLC.Silverlight.ClientApplication.Web
{
    [ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [KnownType(typeof(LocationEdge))]
    [KnownType(typeof(BaseClass))]
    [KnownType(typeof(GameChar))]
    [KnownType(typeof(Channel))]
    [KnownType(typeof(GameCharTemplate))]
    [KnownType(typeof(Template))]
    [KnownType(typeof(StateTemplate))]
    [KnownType(typeof(ItemTemplate))]
    [KnownType(typeof(State))]
    [KnownType(typeof(LocationEdge))]
    [KnownType(typeof(EdgeData))]
    [KnownType(typeof(Area))]
    [KnownType(typeof(Reset))]
    [KnownType(typeof(EffectData))]
    [KnownType(typeof(Item))]
    [KnownType(typeof(GameThingBaseClass))]
    [KnownType(typeof(Ability))]
    [KnownType(typeof(BytesAndType))]
    //[KnownType("ReadKnownTypes")]
    public partial class DataService
    {
        public DataService()
        {
        }

        //static Type[] ReadKnownTypes()
        //{
        //    List<Type> results = new List<Type>();
        //    results.AddRange(TypeProvider.GetInstance().GetAllTypes((t) => t.IsSerializable));

        //    return results.ToArray();
        //}

        [OperationContract, FaultContract(typeof(Fault))]
        public void SaveWorld(int uniqueId)
        {
            WithFaultSupport(() => WorldMap.Instance.Save(null));
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public long CreateItemFromTemplate(int uniqueId, long associatedId, long templateId)
        {
            GameChar chr = associatedId.Find<GameChar>();

            if (chr != null)
            {
                Template t = templateId.Find<Template>();

                if (t != null)
                {
                    Item item = t.CreateInstance<Item>(null);
                    chr.Items.AddItem(item);
                    return item.AssociatedID;
                }
            }

            return 0;
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public long CreateCharFromTemplate(int uniqueId, long templateId, long locationId)
        {
            GameLocation loc = locationId.Find<GameLocation>();

            if (loc != null)
            {
                Template t = templateId.Find<Template>();

                if (t != null)
                {
                    GameChar chr = t.CreateInstance<GameChar>(null);
                    chr.LocationInt = new LocationInt(loc.XYZ);
                    chr.PlaceInWorld(null);
                    return chr.AssociatedID;
                }
            }

            return 0;
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public UsernamePassword Login(int uniqueId, UsernamePassword usernamePassword)
        {
            Global.CheckInit();

            try
            {
                UsernamePassword found = UsernamesPasswords.Instance.DoLogin(usernamePassword);

                if (found == null)
                    return null;

                found.UniqueConnectionId = uniqueId;

                return found;
            }
            catch (Exception e)
            {
                throw new FaultException<Fault>(new Fault(e.ToString()));
            }
        }
        
        [OperationContract, FaultContract(typeof(Fault))]
        public UsernamePassword AssociateIDWithLogin(int uniqueId, UsernamePassword usernamePassword, long id)
        {
            try
            {
                UsernamePassword found = UsernamesPasswords.Instance.DoLogin(usernamePassword);

                found.UniqueConnectionId = uniqueId;

                if (found == null)
                    return null;

                UsernamesPasswords.Instance.AssociateIDWithLogin(found, id);

                return found;
            }
            catch (Exception e)
            {
                throw new FaultException<Fault>(new Fault(e.ToString()));
            }
        }

        [OperationContract, FaultContract(typeof(Fault))]
        public void SendCommand(int uniqueId, string command)
        {
            try
            {
                ConnectionPoint c = ConnectionPoints.GetInstance().GetConnectionPointForUniqueId(uniqueId);

                if (c != null)
                {
                    GameThingBaseClass thing = Everything.Find<GameThingBaseClass>(c.CommandRecipientID);

                    CommandToPerform cmd = command.ParseInputText(thing as GameChar);

                    if (cmd != null)
                        c.SendCommandToGameThing(cmd);
                }
            }
            catch (Exception e)
            {
                throw new FaultException<Fault>(new Fault(e.ToString()));
            }
        }       

        [OperationContract, FaultContract(typeof(Fault))]
        public GameChar SetCurrentlyPlaying(int uniqueId, UsernamePassword usernamePassword, long id)
        {
            try
            {
                UsernamePassword found = UsernamesPasswords.Instance.DoLogin(usernamePassword);

                if (found == null)
                    return null;

                found.UniqueConnectionId = uniqueId;

                if (found.AssociatedIDs.Find(id) != 0)
                {
                    found.SetCurrentlyPlaying(uniqueId, id);
                    GameChar chr = Everything.Find<GameChar>(id);
                    chr.Subscriptions.Subscribe(Subscription.Log | Subscription.RuntimeErrors, OnOffToggle.On);
                    chr.IssueCommand(CommandFactory.CreateLook(id, string.Empty));
                    chr.SendLocationInt(chr.LocationInt, chr.Location);
                    
                    return chr;
                }

                return null;
            }
            catch (Exception e)
            {
                throw new FaultException<Fault>(new Fault(e.ToString()));
            }
        }
    }

    [Serializable]
    [DataContract]
    public class Fault 
    {
        [DataMember]
        public string ErrorMessage { get; set; }

        public Fault(string reason) : base() { ErrorMessage = reason; }
        public Fault() { }
    }    
}
